#include <stdio.h>
#include <stdlib.h>

// 内存可以划分为三块区域：栈区，堆区，静态区
// 栈区存放局部变量，形式参数
// 堆区存放动态内存管理：malloc，free，calloc，realloc等相关的内存空间
// 静态区存放全局变量和静态变量

// malloc能够动态申请和管理内存空间，参数是字节，一次申请多少字节的空间
// malloc 返回void*的指针，因为程序员写库函数的时候不知道我们要用了存什么类型数据
// 开辟的空间储存什么数据就强转成什么类型的指针，作为程序员的我们已经知道1要存储什么类型
// 强制成什么类型，可以让我们更好的控制这片空间

// malloc函数如果申请成功，就返回申请到的空间的起始地址
// 申请失败则返回NULL指针

// int main()
// {
//     int *p = (int *)malloc(10 * sizeof(int));
//     if (p == NULL)
//     {
//         // 当申请太大的空间，会导致申请失败
//         // perror打印错误信息
//         perror("malloc fail");
//         return 1;
//     }

//     // 使用
//     int i = 0;
//     for (i = 0; i < 10; i++)
//     {
//         *(p+i) = i;
//     }
//     for(i=0;i<10;i++){
//         printf("%d ",p[i]);
//     }
//     //malloc申请的空间释放：
//     //free释放----主动
//     //free空不做任何操作
//     //程序退出后，malloc申请的空间，会被操作系统回收---被动
//     //正常情况下谁申请的空间，谁去释放

//     //传递给free需要释放空间的起始地址，free只能释放动态开辟的空间
//     free(p);
//     //虽然p指向的空间已经被释放了，但是p还是指向那块区域，为了安全，把p置空
//     return 0;
// }

// calloc也是用了动态申请空间的
// calloc第一个参数申请几个空间，第二个参数每个空间占多少字节
// 和malloc很相似，但是calloc申请空间后会将空间初始化为0

// int main()
// {
//     int *p = (int *)calloc(10,sizeof(int));
//     if (p == NULL)
//     {
//         perror("malloc fail");
//         return 1;
//     }
//     int i = 0;
//     for (i = 0; i < 10; i++)
//     {
//         printf("%d ", p[i]);
//     }
//     free(p);
//     p=NULL;
//     return 0;
// }

// realloc可以让动态内存管理更加灵活
// realloc第一个参数是之前开辟的内存空间的指针
// 第二个参数是修改后内存字节大小
// 返回值依然是void*，返回的是扩容后的空间地址

// int main()
// {
//     int *p = (int *)calloc(10, sizeof(int));
//     if (p == NULL)
//     {
//         perror("malloc fail");
//         return 1;
//     }
//     int i = 0;
//     for (i = 0; i < 10; i++)
//     {
//         printf("%d ", p[i]);
//     }
//     // 空间不够，希望调整为20个整形的空间
//     // 之所以创建ptr指针，避免realloc开辟失败，赔了夫人又折兵

//     // realloc开辟空间机制：
//     // 原有空间后面直接开辟新空间，返回原空间的地址
//     // 如果原有空间后面不足以开辟需要的空间，会另找地方开辟新空间
//     // 把数据拷贝到新空间，把原空间释放，返回新空间地址
//     int *ptr = (int *)realloc(p, 20 * sizeof(int));
//     if (ptr != NULL)
//     {
//         p = ptr;
//     }
//     free(p);
//     p = NULL;

//     // 如果realloc的地址为NULL，其作用相当于malloc
//     p = realloc(NULL, 10 * sizeof(int));
//     if (ptr != NULL)
//     {
//         p = ptr;
//     }
//     free(p);
//     p = NULL;
//     return 0;
// }

// 可能存在的错误操作

// 对NULL指针的截音乐操作
//  int main(){
//      int *p = (int*)malloc(20);
//      //不做返回值判断，就可能使用NULL指针，解引用
//      *p = 20;
//      return 0;
//  }

// 对动态内存的越界访问
// 开辟十个空间，访问第十一个

// 对非动态开辟空间内存使用free释放

// 使用free释放一块动态开辟内存的一部分

// 对同一块动态内存多次释放

// 忘记对动态开辟的空间释放
